﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;

namespace SchedulerControl.Adorners
{
    public partial class Adorner : UserControl
    {
        
        DispatcherTimer _timerClose;       

        
        public AppointmentItemMetaData MetaData
        {
            get
            {
                if (AdornedObject == null) return null;
                if (AdornedObject.MetaData == null) AdornedObject.MetaData = new AppointmentItemMetaData();
                return AdornedObject.MetaData;
            }
            set
            {
                AdornedObject.MetaData = value;
            }
        }


        public delegate void CloseHandler(object sender);
        public event CloseHandler Closed;

        public delegate void EditHandler(object sender);
        public event EditHandler Edited;

        public delegate void MaximizeHandler(object sender);
        public event MaximizeHandler Maximized;


      



        public delegate void UpdatedHandler();

        /// <summary>
        /// Called whenever the adorner is updated (the AdornedObject parameters change)
        /// </summary>
        public event UpdatedHandler Updated;

        private bool _canRotate = true;
        public bool CanRotate
        {
            get { return _canRotate; }
            set
            {
                if (_canRotate == value) return;
                _canRotate = value;
//                rotate00.IsHitTestVisible = _canRotate;
//                rotate01.IsHitTestVisible = _canRotate;
//                rotate10.IsHitTestVisible = _canRotate;
//                rotate11.IsHitTestVisible = _canRotate;
            }
        }

        private bool _canResize = true;
        public bool CanResize {
            get { return _canResize; }
            set {
                if (_canResize == value) return;
                _canResize = value;
                
//                resize00.IsHitTestVisible = _canResize;
//                resize01.IsHitTestVisible = _canResize;
//                resize10.IsHitTestVisible = _canResize;
//                resize11.IsHitTestVisible = _canResize;

                resizeTop.IsHitTestVisible = _canResize;
                resizeBottom.IsHitTestVisible = _canResize;
//                resizeLeft.IsHitTestVisible = _canResize;
//                resizeRight.IsHitTestVisible = _canResize;
            }
        }

        private bool _canMove = true;
        public bool CanMove {
            get { return _canMove; }
            set {
                if (_canMove == value) return;
                _canMove = value;

                thumbMove.IsHitTestVisible = _canMove;
            }
        }

        /// <summary>
        /// > 0 if over a thumb, 0 if not over a thumb
        /// </summary>
        private int _overThumbCurrently = 0;


        private decimal parentHeight;
        public decimal ParentHeight
        {
            get { return parentHeight; }
            set { parentHeight = value; }
        }


        private decimal parentRatio;
        public decimal ParentRatio
        {
            get { return parentRatio; }
            set { parentRatio = value; }
        }

        private double _x = 100;
        private double _y = 0;
        private double _angle = 0;
        private Dictionary<Thumb, DragData> _dragData = new Dictionary<Thumb, DragData>();
        private const double PI = 3.14159265358979323846264338327950288;

        private IAdornedObject _adornedObject = null;
        private IAdornerFrame _adornerFrame = null;
        private ICursor _cursor = null;

        public double X
        {
            get { return _x; }
            set
            {
                _x = value;
                trTranslate.X = _x;
            }
        }

        public double Y
        {
            get { return _y; }
            set
            {
                _y = value;
                trTranslate.Y = _y;
            }
        }

        public IAdornedObject AdornedObject
        {
            get { return _adornedObject; }
            set { _adornedObject = value; }
        }


        private void InvokeUpdated()
        {
            if (Updated != null) Updated();
        }

        /// <summary>
        /// Sets the object that is displayed within this adorner
        /// The adorner will move around the object set
        /// </summary>
        /// <param name="notify">the object being adorned</param>
        public void SetAdornedObject(IAdornedObject notify)
        {
            AdornedObject = notify;
            _x = AdornedObject.X;
            _y = AdornedObject.Y;
            _angle = AdornedObject.Angle;

            Width = AdornedObject.ObjectWidth;
            Height = AdornedObject.ObjectHeight;
            trTranslate.X = _x;
            trTranslate.Y = _y;
            trRotate.Angle = _angle;
        }

        private Rect _bounds = new Rect(0, 0, 0, 0);
        private bool _hasBounds = false;

        /// <summary>
        /// Sets the bounding rectangle for this adorner
        /// The bounding rectangle is respected for move and size, but not rotate
        /// </summary>
        public void SetBounds(double x, double y, double width, double height)
        {
            _bounds.X = x;
            _bounds.Y = y;
            _bounds.Width = width;
            _bounds.Height = height;
            _hasBounds = true;
        }

        /// <summary>
        /// Removes any bounding restrictions for this adorner
        /// </summary>
        public void ResetBounds()
        {
            _hasBounds = false;
        }

        private double _zoomLevel = 1.0;

        public void SetZoom(double newZoomLevel)
        {
            _zoomLevel = newZoomLevel;
            if (_adornerFrame != null)
            {
                _adornerFrame.SetZoom(_zoomLevel);
            }
        }

        /// <summary>
        /// Sets or removes the curent adorner frame
        /// </summary>
        /// <param name="frame">the new adorner frame to use or null to not use a frame</param>
        public void SetAdornerFrame(IAdornerFrame frame)
        {
            if (_adornerFrame == frame) return;
            if (_adornerFrame != null)
            {
                gridControl.Children.Remove((UIElement)_adornerFrame);
                _adornerFrame.Detached();
            }

            _adornerFrame = frame;
            if (_adornerFrame != null)
            {
                FrameworkElement element = (FrameworkElement)_adornerFrame;
                Grid.SetRowSpan(element, 3);
                Grid.SetColumnSpan(element, 3);
                gridControl.Children.Insert(0, element);
                _adornerFrame.Attached();
                _adornerFrame.SetZoom(_zoomLevel);
                _adornerFrame.SizeChanged(Width, Height);
            }
        }

        public IAdornerFrame GetAdornerFrame() {
            return _adornerFrame;
        }

        /// <summary>
        /// Sets the object that is displayed within this adorner
        /// The adorner will move around the object set
        /// </summary>
        /// <param name="notify">the object being adorned</param>
        public void SetCursor(ICursor cursor)
        {
            _cursor = cursor;
        }

        /// <summary>
        /// Contains dragging information for a specified adorner
        /// </summary>
        private class DragData
        {
            /// <summary>
            /// Angle of the cursor based on the adorner location
            /// </summary>
            public double CursorAngle;

            /// <summary>
            /// Type of drag being performed
            /// </summary>
            public DragType DragType;

            /// <summary>
            /// true if rotating from one of the left adorners, false otherwise
            /// the (RotateIsLeft, RotateIsTop) combination is used to determine angle between the edge where the adorner is at and the center
            /// </summary>
            public bool RotateIsLeft = true;

            /// <summary>
            /// true if rotating from one of the top adorners, false otherwise
            /// the (RotateIsLeft, RotateIsTop) combination is used to determine angle between the edge where the adorner is at and the center
            /// </summary>
            public bool RotateIsTop = true;

            /// <summary>
            /// Calculated on start of rotation, this is the angle between the currently dragged adorner and the center
            /// used to "compensate" the angle between the mouse and center to ensure all 3 points: adorner, mouse, center 
            /// are on the same line
            /// </summary>
            public double RotateAdornerAngleRad = 0;

            /// <summary>
            /// Used for resize adorners only.
            /// Shows how much the width will change when movin mouse one positive unit.D:\Projects\EasyPainter\EasyPainter\Dialogs\
            /// typically -1, 0, or 1
            /// </summary>
            public double WidthChange = 0;

            /// <summary>
            /// Used for resize adorners only.
            /// Shows how much the height will change when movin mouse one positive unit.
            /// typically -1, 0, or 1 
            /// </summary>
            public double HeightChange = 0;

            /// <summary>
            /// Selects left or right edge to not move during resize
            /// -1: right
            /// 1: left
            /// </summary>
            public double HSignInverse = 1;

            /// <summary>
            /// Selects top or bottom edge to not move during resize
            /// -1: top
            /// 1: bottom
            /// </summary>
            public double VSign = 0;
        }

        private enum DragType
        {
            None,
            Size,
            Rotate,
            Move
        }

        private DragType _currentDragOperation = DragType.None;

        public Adorner()
        {
            InitializeComponent();

//            _dragData.Add(resize00, new DragData() { CursorAngle = 45, DragType = DragType.Size, WidthChange = -1, HeightChange = -1, HSignInverse = -1, VSign = 1 });
//            _dragData.Add(resize10, new DragData() { CursorAngle = 135, DragType = DragType.Size, WidthChange = 1, HeightChange = -1, HSignInverse = 1, VSign = 1 });
//            _dragData.Add(resize01, new DragData() { CursorAngle = 135, DragType = DragType.Size, WidthChange = -1, HeightChange = 1, HSignInverse = -1, VSign = -1 });
//            _dragData.Add(resize11, new DragData() { CursorAngle = 45, DragType = DragType.Size, WidthChange = 1, HeightChange = 1, HSignInverse = 1, VSign = -1 });

            _dragData.Add(resizeTop, new DragData() { CursorAngle = 90, DragType = DragType.Size, WidthChange = 0, HeightChange = -1, HSignInverse = -1, VSign = 1 });
            _dragData.Add(resizeBottom, new DragData() { CursorAngle = 90, DragType = DragType.Size, WidthChange = 0, HeightChange = 1, HSignInverse = 1, VSign = -1 });
//            _dragData.Add(resizeLeft, new DragData() { CursorAngle = 0, DragType = DragType.Size, WidthChange = -1, HeightChange = 0, HSignInverse = -1, VSign = 1 });
//            _dragData.Add(resizeRight, new DragData() { CursorAngle = 0, DragType = DragType.Size, WidthChange = 1, HeightChange = 0, HSignInverse = 1, VSign = -1 });

//            _dragData.Add(rotate00, new DragData() { CursorAngle = 0, DragType = DragType.Rotate, RotateIsLeft = true, RotateIsTop = true });
//            _dragData.Add(rotate10, new DragData() { CursorAngle = 90, DragType = DragType.Rotate, RotateIsLeft = false, RotateIsTop = true });
//            _dragData.Add(rotate01, new DragData() { CursorAngle = 270, DragType = DragType.Rotate, RotateIsLeft = true, RotateIsTop = false });
//            _dragData.Add(rotate11, new DragData() { CursorAngle = 180, DragType = DragType.Rotate, RotateIsLeft = false, RotateIsTop = false });

            _dragData.Add(thumbMove, new DragData() { CursorAngle = 0, DragType = DragType.Move });


            
            _timerClose = new DispatcherTimer();
            _timerClose.Interval = TimeSpan.FromMilliseconds(500);
            _timerClose.Tick += new EventHandler(_timerClose_Tick);


        }

        void _timerClose_Tick(object sender, EventArgs e)
        {
            HideToolbar(); 
        }

       


        #region Rotate
        Point _mousePosRelativeToThis;
        private void rotate_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
        {
            _currentDragOperation = DragType.Rotate;
            _draggedThumb = (Thumb)sender;
            Point result = trRotate.Inverse.Transform(new Point(e.HorizontalOffset - _x, e.VerticalOffset - _y));
            _mousePosRelativeToThis.X = result.X;
            _mousePosRelativeToThis.Y = result.Y;
            DragData data = _dragData[_draggedThumb];
            data.RotateAdornerAngleRad = GetRotateAdornerAngle(data, Width / 2, Height / 2);
        }
        #endregion


        #region Dragging and Cursors
        private void thumb_MouseEnter(object sender, MouseEventArgs e)
        {
            _overThumbCurrently++;
            Thumb thumb = (Thumb)sender;
            DragData data = _dragData[thumb];
            ShowCursor(data.DragType, e.GetPosition(this), data.CursorAngle);
            ShowToolbar();
        }

        private void thumb_MouseLeave(object sender, MouseEventArgs e)
        {
            _overThumbCurrently--;
            if (_draggedThumb == null)
            {
                ShowDefaultCursor();
            }
            this._timerClose.Start();  
        }

        Point _lastMousePos;
        bool _lastMousePosInitialized = false;

        /// <summary>
        /// Retrieves the angle between the edge for a given rotate adorner and the center
        /// </summary>
        /// <param name="data"></param>
        /// <param name="centerX"></param>
        /// <param name="centerY"></param>
        /// <returns></returns>
        private double GetRotateAdornerAngle(DragData data, double centerX, double centerY)
        {
            double x, y;
            if (data.RotateIsLeft)
            {
                x = centerX;
            }
            else
            {
                x = -centerX;
            }

            if (data.RotateIsTop)
            {
                y = centerY;
            }
            else
            {
                y = -centerY;
            }

            return Math.Atan2(x, y) - PI;
        }

        private double RadFromDeg(double angle)
        {
            return angle * PI / 180;
        }

        private double DegFromRad(double angle)
        {
            return angle * 180 / PI;
        }

        private void thumb_MouseMove(object sender, MouseEventArgs e)
        {
            DragData dragData;
            _mousePosRelativeToThis = e.GetPosition(this);
            if (!_lastMousePosInitialized)
            {
                _lastMousePos.X = _mousePosRelativeToThis.X;
                _lastMousePos.Y = _mousePosRelativeToThis.Y;
                _lastMousePosInitialized = true;
                return;
            }
            Point delta = new Point();
            delta.X = _mousePosRelativeToThis.X - _lastMousePos.X;
            delta.Y = _mousePosRelativeToThis.Y - _lastMousePos.Y;
            UpdateCursorPos(_mousePosRelativeToThis);
            switch (_currentDragOperation)
            {
                case DragType.Move:
                    if (_hasBounds)
                    {
                        //double newX = _x + delta.X;
                        double newY = _y + delta.Y;
//                        if (newX < _bounds.X)
//                        {
//                            _x = _bounds.X;
//                        }
//                        else
//                        {
//                            if ((newX + Width) > _bounds.Right)
//                            {
//                                _x = _bounds.Right - Width;
//                            }
//                            else
//                            {
//                                _x = newX;
//                            }
//                        }

                        if (newY < _bounds.Y)
                        {
                            _y = _bounds.Y;
                        }
                        else
                        {
                            if ((newY + Height) > _bounds.Bottom)
                            {
                                _y = _bounds.Bottom - Height;
                            }
                            else
                            {
                                _y = newY;
                            }
                        }
                    }
                    else
                    {
                        //_x += delta.X;
                        _y += delta.Y;
                    }
                    //trTranslate.X = _x;

//
//                    decimal moveSteps = (decimal)(parentHeight / 48);
//                    decimal moveMod = (decimal)(((decimal)_y) % moveSteps);
//                    decimal tempY = (decimal)_y;
//                    if (moveMod != 0)
//                    {
//                        tempY -= moveMod;
//                    }else
//                    {
//                        tempY = (decimal)_y;
//                    }

                    trTranslate.Y = (double)_y;
                    if (AdornedObject != null)
                    {
                        //_adornedObject.X = _x;

                        AdornedObject.Y = (double)_y;

                    }
                    _lastMousePos.Y = (double)_y;
                   
                    InvokeUpdated();
                    
                    
                    

                    break;

                case DragType.Rotate:
                    {
                        double w2 = Width / 2;
                        double h2 = Height / 2;
                        Point centerOfRotation = new Point(_x + w2, _y + h2);
                        dragData = _dragData[_draggedThumb];
                        // calculate the angle between the mouse and the center of rotation and subtract the adorner angle to make sure
                        // the adorner, mouse and center of rotation will end up on the same line
                        _angle = DegFromRad(Math.Atan2(centerOfRotation.X - _mousePosRelativeToThis.X, -centerOfRotation.Y + _mousePosRelativeToThis.Y) +
                            dragData.RotateAdornerAngleRad);
                        trRotate.Angle = _angle;
                        if (AdornedObject != null)
                        {
                            AdornedObject.Angle = _angle;
                        }
                        UpdateCursorAngle();
                        InvokeUpdated();
                    }
                    break;

                case DragType.Size:
                    // resize algorithm: 
                    // 1. find the distance between the line passing through the point the mouse was last at 
                    //   and the current point - this is the distance to move the edge
                    // 2. Move the edge based on the current adorner (dragData)
                    Point rotatedDelta = trRotate.Inverse.Transform(delta);
                    dragData = _dragData[_draggedThumb];

                    double widthInc = rotatedDelta.X;
                    double heightInc = rotatedDelta.Y;
                   
                    if (_preserveCenterOnResize)
                    {
                        // since we preserve the center, 
                        // width and height change should be double when the mouse if moved one pixel 
                        // so that the cursor will follow the mouse
                        widthInc *= dragData.WidthChange * 2;
                        heightInc *= dragData.HeightChange * 2;

                        // check for min width and height
                        if (Width + widthInc < 0)
                        {
                            widthInc = -Width;
                        }
                        if (Height + heightInc < 0)
                        {
                            heightInc = -Height;
                        }

                        double widthInc2 = widthInc / 2;
                        double heightInc2 = heightInc / 2;

                        Width += widthInc;
                        Height += heightInc;

                        // the difference between the center positions before the rotation is (-widthInc2, -widthInc2)
                        // the center is moved by (-widthInc2, -widthInc2) in order to compensate for the difference,
                        // which effectively will preserve the center
                        _x -= widthInc2;
                        _y -= heightInc2;
                    }
                    else
                    {
                        widthInc *= dragData.WidthChange;
                        heightInc *= dragData.HeightChange;

                        // check for min width and height
                        if (Width + widthInc < 0)
                        {
                            widthInc = -Width;
                        }
                        if (Height + heightInc < 0)
                        {
                            heightInc = -Height;
                        }

                        double widthInc2 = widthInc / 2;
                        double heightInc2 = heightInc / 2;

                        // HSign, VSign combinations:
                        // +, - = top-left
                        // -, - = top-right
                        // +, + = bototm-left
                        // -, + = bottom-right

                        Point vectorToNewCenterAfterRotation = new Point(dragData.HSignInverse * widthInc2, dragData.VSign * heightInc2);
                        Point pointToKeepOrigAfterSize = trRotate.Inverse.Transform(vectorToNewCenterAfterRotation);

                        double dx = pointToKeepOrigAfterSize.X - widthInc2;
                        double dy = pointToKeepOrigAfterSize.Y + heightInc2;

                        Width += widthInc;
                        Height += heightInc;
                        _x += dx;
                        _y -= dy;
                    }

                    // check for bounds: note if we have bounds, we assume rotation angle is zero
                    if (_hasBounds)
                    {
                        if (_x < _bounds.X)
                        {
                            Width -= (_bounds.X - _x);
                            _x = _bounds.X;
                        }

                        if ((_x + Width) > _bounds.Right)
                        {
                            Width = _bounds.Right - _x;
                        }

                        if (_y < _bounds.Y)
                        {
                            Height -= (_bounds.Y - _y);
                            _y = _bounds.Y;
                        }

                        if ((_y + Height) > _bounds.Bottom)
                        {
                            Height = _bounds.Bottom - _y;
                        }
                    }

//                    moveSteps = (decimal)(parentHeight / 48);
//                    moveMod = (decimal)(((decimal)_y) % moveSteps);
//                    Y = (decimal)_y;
//                    if (moveMod != 0)
//                    {
//                        Y -= moveMod;
//                    }else
//                    {
//                        Y = (decimal)_y;
//                    }
//
//                    moveSteps = (decimal)(parentHeight / 48);
//                   
//
//                    decimal bottomMoveMod = (decimal)(((decimal)(Height)) % moveSteps);
//                    decimal Bottom = (decimal) Height;
//
//
//                    if (bottomMoveMod != 0)
//                    {
                        //Bottom -= bottomMoveMod;
//                        Height = (double)Bottom;
//                    }else
//                    {
//                        Bottom = (decimal) Height;
//                    }

                    trTranslate.X = _x;
                    trTranslate.Y = _y;
                    if (AdornedObject != null)
                    {
                        AdornedObject.X = _x;
                        AdornedObject.Y = _y;
                        AdornedObject.ObjectWidth = Width;
                        AdornedObject.ObjectHeight = Height;
                    }
                    InvokeUpdated();
                    break;

            }
            _lastMousePos.X = _mousePosRelativeToThis.X;
            _lastMousePos.Y = _mousePosRelativeToThis.Y;
        }

        bool _preserveCenterOnResize = false;

        public void StartMoveDrag()
        {
            this.Visibility = System.Windows.Visibility.Visible;
            
            _lastMousePosInitialized = false;
            thumb_DragStarted(thumbMove, null);
        }

        public void EndMoveDrag()
        {
            this.Visibility = System.Windows.Visibility.Collapsed;  
        }

        private void thumb_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
        {
            _currentDragOperation = _dragData[(Thumb)sender].DragType;
            _draggedThumb = (Thumb)sender;
            var adornedObject = (AdornedObject)AdornedObject;
            
            

            
            
        }



        public void ShowToolbar()
        {
            this._timerClose.Stop();
            if (this.trTranslate.Y < 18)
            {
                topToolbar.Visibility = System.Windows.Visibility.Collapsed;
                bottomToolbar.Visibility = System.Windows.Visibility.Visible;   
            }else
            {
                topToolbar.Visibility = System.Windows.Visibility.Visible;
                bottomToolbar.Visibility = System.Windows.Visibility.Collapsed;   
            }
            
 
        }


        public void HideToolbar()
        {
            topToolbar.Visibility = System.Windows.Visibility.Collapsed;
            bottomToolbar.Visibility = System.Windows.Visibility.Collapsed; 

        }
        


        private void thumb_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
        {
            _currentDragOperation = DragType.None;
            _draggedThumb = null;
            if (_overThumbCurrently == 0)
            { // if not over thumb
                ShowDefaultCursor();
            }


            decimal quarterHourHeight = parentHeight/96;
            decimal halfHourHeight = parentHeight/48;

            decimal currentY = (decimal)trTranslate.Y;
            decimal currentH = (decimal)Height;
            decimal currentYReminder = (currentY%halfHourHeight);
            decimal currentHReminder = (currentH % halfHourHeight);
            //decimal y1 = (decimal)trTranslate.Y;  
            //decimal difference = 

            //if (Math.Abs(currentYReminder - quarterHourHeight) < 1) return;
            if(currentYReminder <=quarterHourHeight)
            {
                Y = (double)(currentY - currentYReminder);
                AdornedObject.Y = Y;
                trTranslate.Y = Y;
            }
            else
            {
               Y = (double)(currentY + (halfHourHeight -currentYReminder));
               AdornedObject.Y = Y;
               trTranslate.Y = Y;
            }


            if (Math.Abs(currentHReminder - quarterHourHeight) < 1) return;
            if (currentHReminder <= quarterHourHeight)
            {
                Height = (double)(currentH - currentHReminder);
                AdornedObject.ObjectHeight = Height;
            }
            else
            {
                Height = (double)(currentH + (halfHourHeight - currentHReminder));
                AdornedObject.ObjectHeight = Height;
            }

            this.MetaData.StartTime = HeightToDateTime((decimal)Y);
            this.MetaData.EndTime = HeightToDateTime((decimal) Y + (decimal) Height);
             var adornedObject = (AdornedObject)AdornedObject;
            ScheduleItemControl scheduleItemControl = (ScheduleItemControl)adornedObject.AdornedElement;
            this.MetaData.ItemDate = scheduleItemControl.CurrentViewDate; 
             

        }



//        private Rect CalculateBoundry(ScheduleItemControl scheduleItemControl)
//        {
//            ScheduleItemControl _topScheduleItemControl = null;
//            ScheduleItemControl _bottomScheduleItemControl = null;
//            decimal _yDifferenceNew1 = 0;
//            decimal _yDifferenceOld1 = 0;
//            decimal _yDifferenceNew2 = 0;
//            decimal _yDifferenceOld2 = 0;
//
//            foreach (ScheduleItemControl sic in scheduleItems)
//            {
//                if (Canvas.GetTop(sic) + sic.Height <= Canvas.GetTop(scheduleItemControl))
//                {
//                    _yDifferenceNew1 = (decimal)(Canvas.GetTop(scheduleItemControl) - (Canvas.GetTop(sic) + sic.Height));
//
//                    if (_yDifferenceOld1 == 0 || _yDifferenceNew1 <= _yDifferenceOld1)
//                    {
//                        _topScheduleItemControl = sic;
//                        _yDifferenceOld1 = _yDifferenceNew1;
//                    }
//                }
//
//                if (Canvas.GetTop(scheduleItemControl) + scheduleItemControl.Height <= Canvas.GetTop(sic))
//                {
//                    _yDifferenceNew2 = (decimal)(Canvas.GetTop(sic) - (Canvas.GetTop(scheduleItemControl) + scheduleItemControl.Height));
//
//                    if (_yDifferenceOld2 == 0 || _yDifferenceNew2 <= _yDifferenceOld2)
//                    {
//                        _bottomScheduleItemControl = sic;
//                        _yDifferenceOld2 = _yDifferenceNew2;
//                    }
//                }
//            }
//
//            decimal _topBoundry = 0;
//            decimal _bottomBoundry = _currentContainerHeight;
//
//            if (_topScheduleItemControl != null)
//            {
//                _topBoundry = (decimal)(Canvas.GetTop(_topScheduleItemControl) + _topScheduleItemControl.Height);
//            }
//
//            if (_bottomScheduleItemControl != null)
//            {
//                _bottomBoundry = (decimal)(Canvas.GetTop(_bottomScheduleItemControl));
//            }
//
//            Rect rect = new Rect(0, (double)_topBoundry, (double)_currentContainerWidth, (double)(_bottomBoundry - _topBoundry));
//            scheduleItemControl.MoveBoundry = rect;
//
//            return rect;
//        }


        private decimal DateTimeToHeight(DateTime dateTime)
        {
            int hour = dateTime.Hour;
            int minute = dateTime.Minute;
            decimal oneMinuteHeight = parentHeight / (24 * 60);
            decimal timeHeight = oneMinuteHeight * ((hour * 60) + minute);

            return timeHeight;
        }


        private DateTime HeightToDateTime(decimal height)
        {
            var adornedObject = (AdornedObject)AdornedObject;
            ScheduleItemControl scheduleItemControl = (ScheduleItemControl)adornedObject.AdornedElement;
            decimal oneMinuteHeight = parentHeight / (24 * 60);
            decimal minuteCount = height / oneMinuteHeight;
            int hour = (int)(minuteCount / 60);
            int minute = (int)(minuteCount % 60);
            DateTime dateTime = new DateTime(scheduleItemControl.CurrentViewDate.Year, scheduleItemControl.CurrentViewDate.Month, scheduleItemControl.CurrentViewDate.Day, hour, minute, 0);
            return dateTime;
        }

        private void thumbMove_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if(_currentDragOperation ==  DragType.Move)
            {
                decimal moveSteps = (decimal)(parentHeight / 48);
                decimal moveMod = (decimal)(((decimal)_y) % moveSteps);
                
                if (moveMod != 0)
                {
                    _y -= (double)moveMod;
                }
            }
            _currentDragOperation = DragType.None;
            _draggedThumb = null;
            if (_overThumbCurrently == 0)
            { // if not over thumb
                ShowDefaultCursor();
            }
        }

        private void ShowDefaultCursor()
        {
            _cursor.Show(CursorType.Default);
        }

        private void ShowCursor(DragType type, Point pos, double angle)
        {
            CursorType cursorType;
            switch (type)
            {
                case DragType.Move:
                    cursorType = CursorType.Move;
                    break;

                case DragType.Rotate:
                    cursorType = CursorType.Rotate;
                    break;

                case DragType.Size:
                    cursorType = CursorType.Size;
                    break;

                case DragType.None:
                    cursorType = CursorType.Default;
                    break;

                default:
                    throw new ArgumentException("Unknown drag type: " + type.ToString());
            }

            _cursor.Show(cursorType);
            _currentCursorData.InitAngle = angle;

            UpdateCursorAngle();
            UpdateCursorPos(pos);
        }

        private void UpdateCursorAngle()
        {
            _cursor.SetAngle(_currentCursorData.InitAngle + _angle);
        }
        
        private Point _posOffset = new Point(0, 0);

        public void SetCursorPosOffset(Point offset)
        {
            _posOffset = offset;
        }

        private void UpdateCursorPos(Point pos)
        {
            _cursor.SetPos(pos.X + _posOffset.X, pos.Y + _posOffset.Y);
        }

        Thumb _draggedThumb = null;
        CursorData _currentCursorData = new CursorData();
        #endregion

        private void gridControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (_adornerFrame != null)
            {
                // note: do not use e.NewSize.Width, e.NewSize.Height, since they are truncated and precision may be lost
                _adornerFrame.SizeChanged(Width, Height);
            }
        }

        private int RobustRound(double value)
        {
            int valueInt = (int)value;
            double frac = value - valueInt;
            if (frac >= 0.5) return valueInt + 1;
            return valueInt;
        }

        private class CursorData
        {
            public double InitAngle;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            
        }

        private void btnClose_Click(object sender, RoutedEventArgs e)
        {
            if (Closed != null) Closed(this);

        }

        private void btnEdit_Click(object sender, RoutedEventArgs e)
        {
            if (Edited != null) Edited(this);
            SetEditMode();
            
        }

        private void btnMaximize_Click(object sender, RoutedEventArgs e)
        {
            if (Maximized != null) Maximized(this);
        }

       



        public void SetEditMode()
        {
            var adornedObject = (AdornedObject)AdornedObject;
            ScheduleItemControl scheduleItemControl = (ScheduleItemControl)adornedObject.AdornedElement;

            if (scheduleItemControl.IsInEditMode)
            {
                thumbMove.Visibility = System.Windows.Visibility.Collapsed;
            }
            else
            {
                thumbMove.Visibility = System.Windows.Visibility.Visible;
            }

        }

        private void grid_MouseEnter(object sender, MouseEventArgs e)
        {
            ShowToolbar(); 
        }

        private void grid_MouseLeave(object sender, MouseEventArgs e)
        {
            this._timerClose.Start();  
        }

        
    }
}
